package com.segersten.kalaha


import com.google.appengine.api.memcache.MemcacheServiceFactory
import com.google.appengine.api.memcache.MemcacheService
import com.segersten.kalaha.domain.Event
import com.segersten.kalaha.domain.EventType
import grails.converters.*

class TestController {

    def index = { 	}
    
    
    def asserts = {
    	render(text:"1. Test assert true<br>")
    	LogicAssert.assertTrue(true, "Assert true failed")	
    	render(text:"OK")
    	
    	render(text:"<hr>2. Test assert false<br>")
    	try {
    		LogicAssert.assertTrue(false, "Assert false failed")
    		render(text:"Assert false failed")
    	} catch(IllegalStateException e) {
    		render(text:"OK")
    	}
    	
    	render(text:"<hr>3. Test assert applogic<br>")
    	try {
    		LogicAssert.assertTrue(EventType.GAME_FINISHED==EventType.GAME_CREATED, "Unexpected event " + EventType.GAME_FINISHED)
    		render(text:"Assert logic failed")
    	} catch(IllegalStateException e) {
    		render(text:"OK")
    	}
    	
    }
    
    def map = {	
	    def eventLogicMap = [ (EventType.GAME_CREATED) : new KalahaCreatedLogic(),
					 (EventType.PLAYER_1_JOINED) : new KalahaPlayer1JoinedLogic(),
					 (EventType.PLAYER_2_JOINED) : new KalahaPlayer2JoinedLogic(),
					 (EventType.PLAYER_1_ACTION) : new KalahaPlayer1ActionLogic(),
					 (EventType.PLAYER_2_ACTION) : new KalahaPlayer2ActionLogic(),
					 (EventType.GAME_FINISHED) : new KalahaGameFinishedLogic()]
					 
		def r = eventLogicMap.get(EventType.GAME_CREATED)
		if (r) {
			render(text:"OK " + EventType.GAME_CREATED)
		} else {
			render(text:"ERROR - null")
		}
    }
    
    def logic = {
    	render(text:"1. Test game logic - happy case!<br>")
    	Player player1 = new Player(sessionId:"123",
									accessToken:"DebugModeNoTokenAvailable",
									userId:"asd",
									name:"QWE",
									type:"DBG",
									created:new Date())
		Player player2 = new Player(sessionId:"456",
									accessToken:"DebugModeNoTokenAvailable",
									userId:"zxc",
									name:"ERT",
									type:"DBG",
									created:new Date())
									
    	BoardSession bs = new BoardSession(sessionId:"Test",
    										player1:player1,
    										player2:player2,
    										events:Event.createEventList())
    	BoardSessionCache bsc = new BoardSessionCache()
    	bsc.put(bs)
    	bs.addEvent(EventType.GAME_CREATED,GameType.KALAHA)
    	LogicAssert.assertTrue(bs.events[0].type==EventType.GAME_CREATED, "Unexpected event")
    	LogicAssert.assertTrue(bs.getLastEvent().type==EventType.GAME_CREATED, "Unexpected event - " + bs.getLastEvent().type)
    	bs.board = new Board(stones:36, buckets:[0,3,3,3,3,3,3,0,3,3,3,3,3,3])
		
		bs.addEvent(EventType.PLAYER_1_JOINED, "Hej")
		bs.addEvent(EventType.PLAYER_2_JOINED, "He2")
		LogicAssert.assertTrue(bs.events.size()==3, "Unexpected size, expected 3 was "+bs.events.size())
		
		bs.addEvent(EventType.PLAYER_1_ACTION, "5")
		LogicAssert.assertTrue(bs.events.size()==4, "Unexpected size, expected 4 was "+bs.events.size())
		LogicAssert.assertTrue(bs.board.buckets[5]==0, "Unexpected value in bucket 5, expected 0 but was " + bs.board.buckets[5])
		LogicAssert.assertTrue(bs.board.buckets[6]==4, "Unexpected value in bucket 6, expected 4 but was " + bs.board.buckets[6])
		LogicAssert.assertTrue(bs.board.buckets[7]==1, "Unexpected value in bucket 7, expected 1 but was " + bs.board.buckets[7])
		LogicAssert.assertTrue(bs.board.buckets[8]==4, "Unexpected value in bucket 8, expected 4 but was " + bs.board.buckets[8])
		LogicAssert.assertTrue(bs.board.buckets.subList(1,7).sum()==16, "Expected 16, got " + bs.board.buckets.subList(1,7).sum())
		LogicAssert.assertTrue(bs.board.buckets.subList(8,14).sum()==19, "Expected 19, got " + bs.board.buckets.subList(1,7).sum())
		
		LogicAssert.assertTrue(bs.getLastEvent().type==EventType.PLAYER_1_ACTION, "Unexpected event - " + bs.getLastEvent().type)
		LogicAssert.assertTrue(bs.nextActor==Actor.PLAYER_2, "Unexpected actor - " + bs.nextActor)
		// force almost empty side
		bs.board.buckets[13]==1
		bs.board.buckets[12]==0
		bs.board.buckets[11]==0
		bs.board.buckets[10]==0
		bs.board.buckets[9]==0
		bs.board.buckets[8]==0
		bs.addEvent(EventType.PLAYER_2_ACTION, "13")
		LogicAssert.assertTrue(bs.board.buckets[13]==0, "Unexpected value in bucket 13, expected 0 but was " + bs.board.buckets[13])
		LogicAssert.assertTrue(bs.board.buckets[0]==1, "Unexpected value in bucket 0, expected 0 but was " + bs.board.buckets[0])
		LogicAssert.assertTrue(bs.getLastEvent().type==EventType.PLAYER_2_ACTION, "Unexpected event - " + bs.getLastEvent().type)
		LogicAssert.assertTrue(bs.nextActor==Actor.PLAYER_1, "Unexpected actor - " + bs.nextActor)
		
		
		SessionTicket.withTransaction { status ->
		// Create tickets so time out logic can clean up
		SessionTicket t1 = new SessionTicket(ticketId:"123",
				ownerId:bs.player1.userId,
				created:new Date(),
					lastUpdated:new Date(),
					sessionId:null,
					joinedSession:null,
					acceptBotOpponnent:true,
					ownerIsBot:false)
		t1.save()
    	}
		SessionTicket.withTransaction { status ->
			// Create tickets so time out logic can clean up
			SessionTicket t1 = new SessionTicket(ticketId:"123",
					ownerId:bs.player2.userId,
					created:new Date(),
						lastUpdated:new Date(),
						sessionId:null,
						joinedSession:null,
						acceptBotOpponnent:true,
						ownerIsBot:false)
			t1.save()
			}
		
		
		SessionTicket ticket1 = SessionTicket.find("SELECT FROM SessionTicket st WHERE st.ownerId = :id", [id:player1.userId])
		LogicAssert.assertTrue(ticket1!=null, "Ohno " + ticket1)
		
		bs.nextActor=Actor.PLAYER_1 
		bs.addEvent(EventType.PLAYER_1_TIMEOUT,"timeout")
    	LogicAssert.assertTrue(bs.events[6].type ==EventType.GAME_FINISHED, "Unexpected event ")
    	LogicAssert.assertTrue(bs.events.size()==7, "Unexpected size, expected 6 was "+bs.events.size())
    	LogicAssert.assertTrue(bs.getLastEvent().type==EventType.GAME_FINISHED, "Unexpected event - " + bs.getLastEvent().type)
		LogicAssert.assertTrue(bs.nextActor==Actor.NONE, "Unexpected actor, expected NONE was "+bs.nextActor)
		render(text:"OK<br>")
    	
    	render(text:"<hr>2. Test game logic - two GAME_FINISHED case<br>")	
    	bs.addEvent(EventType.GAME_FINISHED,null)	
    	LogicAssert.assertTrue(bs.events.size()==7, "Unexpected size, expected 5 was "+bs.events.size())
    	LogicAssert.assertTrue(bs.nextActor==Actor.NONE, "Unexpected actor, expected NONE was "+bs.nextActor)
    	
    	render(text:"OK<br>")
    }
    
    def test = {
    	render(text:"1. Put GameSession to cache<br>")
    	Player player1 = new Player(sessionId:"123",
									accessToken:"DebugModeNoTokenAvailable",
									userId:"asd",
									name:"QWE",
									type:"DBG",
									created:new Date())
		Player player2 = new Player(sessionId:"456",
									accessToken:"DebugModeNoTokenAvailable",
									userId:"zxc",
									name:"ERT",
									type:"DBG",
									created:new Date())
									
    	BoardSession bs = new BoardSession(sessionId:"Test",
    										player1:player1,
    										player2:player2,
    										events:Event.createEventList())
    	BoardSessionCache bsc = new BoardSessionCache()
    	LogicAssert.assertTrue(bs.nextActor == Actor.ENGINE, "Unexpected actor ${bs.nextActor}")
    	bsc.put(bs)
    	bs.addEvent(EventType.GAME_CREATED,GameType.KALAHA)
    	LogicAssert.assertTrue(bs.nextActor == Actor.ENGINE, "Unexpected actor ${bs.nextActor}")
    	LogicAssert.assertTrue(bs.events.size()==1, "Should be 1 element in bs.events was ${bs.events.size()}")
    	bs.addEvent(EventType.PLAYER_1_JOINED,null)
    	LogicAssert.assertTrue(bs.nextActor == Actor.ENGINE, "Unexpected actor ${bs.nextActor}")
    	bs.addEvent(EventType.PLAYER_2_JOINED,null)
    	LogicAssert.assertTrue(bs.nextActor == Actor.PLAYER_1, "Unexpected actor ${bs.nextActor}")
    	
    	render(text:"OK")
    	render(text:"<hr>2. Read GameSession from cache<br>")
    	bs = bsc.get(bs.sessionId)	
    	render(text:"ID ${bs.sessionId}<br>")
    	render(text:"Gametype ${bs.gameType}<br>")
    	render(text:"Name p1 ${bs.player1.name}<br>")	
    	render(text:"Name p2 ${bs.player2.name}<br>")
    	render(text:"Events ${bs.getEventsInfo()}<br>")	
    	render(text:"OK")
    }
    
    def cache = {
    	MemcacheService cache = MemcacheServiceFactory.getMemcacheService("TestCache.1")
    	render(text:"1. Add player to cache")
    	Player player = new Player(sessionId:"123",
									accessToken:"DebugModeNoTokenAvailable",
									userId:"asd",
									name:"QWE",
									type:"DBG",
			     					created:new Date())
			     					
		cache.put("1",player)
		render(text:"<br>OK")
		render(text:"<hr>2. Add Board to cache")
    	Board board = new Board(player1:true,
    							player2:false)
			     					
		cache.put("2",board)
		render(text:"<br>OK")
		render(text:"<hr>3. Add BoardSession to cache")
    	BoardSession boardSession = new BoardSession(player1:player,
    								   player2:player,
    								   sessionId:"apa",
    								   board:board,
    								   events:Event.createEventList())
		cache.put("3",boardSession)
		render(text:"<br>OK")
    }
    
    def connect = {
		Player player = new Player(sessionId:"123",
		accessToken:"DebugModeNoTokenAvailable",
		userId:"ABC",
		name:"QWE",
		type:"DBG",
		created:new Date())
		player.channelToken = Channel.createToken(player)
		PlayerCache pc = new PlayerCache()
		pc.put(player)
		
		[player:player]
    }
	

    
	def sendToClient = {
		PlayerCache pc = new PlayerCache()
		Player player = pc.getByUserId("ABC")
		
		Channel.sendUpdateToClients("Hi there", player)
		
		render(text:"OK ${player.channelToken}")
	}
	
    def json = {
    	render(text:"1. Render BoardSession as JSON<hr>")
    	Player player1 = new Player(sessionId:"123",
									accessToken:"DebugModeNoTokenAvailable",
									userId:"asd",
									name:"QWE",
									type:"DBG",
			     					created:new Date())
		Player player2 = new Player(sessionId:"456",
									accessToken:"DebugModeNoTokenAvailable",
									userId:"sdf",
									name:"WER",
									type:"DBG",
			     					created:new Date())
		BoardSession boardSession = new BoardSession(sessionId:"TEST",
    												player1:player1,
    												player2:player2,
    												gameType:GameType.KALAHA,
    												events:Event.createEventList())
    				
		render(contentType:"text/json") { 
										  element player1:[name:boardSession.player1.name, userId:player1.userId]
										  element player2:[name:boardSession.player2.name, userId:player2.userId]
										  element events:boardSession.events
										  element gameType:boardSession.gameType.name()
										} 
    }
	
	def board = {
		render(text:"1. Test board logic<hr>")
		render(text:"step 1<br>")
		Board b = new Board(stones:36, buckets:[0,3,3,3,3,3,3,0,3,3,3,3,3,3])
		def res = b.move(4,1,6)
		LogicAssert.assertTrue(res.nextPlayer == false, "Unexpected result " + res)
		LogicAssert.assertTrue(res.gameFinished == false, "Unexpected result " + res)
		List expected = [0,3,3,3,0,4,4,1,3,3,3,3,3,3]
		b.buckets.eachWithIndex { value, index -> 
		  LogicAssert.assertTrue(expected[index] == value, "Unexpected result at ${index} --> ${expected[index]} != ${value}")
		}
		render(text:"step 2<br>")
		res = b.move(1,1,6)
		expected = [0,0,4,4,0,4,4,5,3,3,0,3,3,3]
		LogicAssert.assertTrue(res.nextPlayer == true, "Unexpected result " + res)
		LogicAssert.assertTrue(res.gameFinished == false, "Unexpected result " + res)
		b.buckets.eachWithIndex { value, index ->
		  LogicAssert.assertTrue(expected[index] == value, "Unexpected result at ${index} --> ${expected[index]} != ${value}")
		}
		render(text:"new Board 1 step 1<br>")
		b = new Board(stones:36, buckets:[4,1,5,4,3,9,0,10,0,0,0,0,0,0])
		res = b.move(1,1,6)	
		expected = [4,0,6,4,3,9,0,10,0,0,0,0,0,0]
		LogicAssert.assertTrue(res.nextPlayer == false, "Unexpected result " + res)
		LogicAssert.assertTrue(res.gameFinished == false, "Unexpected result " + res)
		b.buckets.eachWithIndex { value, index ->
			LogicAssert.assertTrue(expected[index] == value, "Unexpected result at ${index} --> ${expected[index]} != ${value}")
		}
		render(text:"new Board 2 step 1<br>")
		b = new Board(stones:36, buckets:[14,1,1,2,0,0,1,8,0,0,0,0,0,9])
		res = b.move(13,8,13)
		expected = [17,2,2,3,1,0,2,8,1,0,0,0,0,0]
		LogicAssert.assertTrue(res.nextPlayer == true, "Unexpected result " + res)
		LogicAssert.assertTrue(res.gameFinished == false, "Unexpected result " + res)
		b.buckets.eachWithIndex { value, index ->
			LogicAssert.assertTrue(expected[index] == value, "Unexpected result at ${index} --> ${expected[index]} != ${value}")
		}
		
		render(text:"new Board 3 step 1<br>")
		b = new Board(stones:36, buckets:[17,0,0,0,0,0,0,18,0,0,0,0,0,1])
		res = b.move(13,8,13)
		expected = [18,0,0,0,0,0,0,18,0,0,0,0,0,0]
		LogicAssert.assertTrue(res.nextPlayer == false, "Unexpected result " + res)
		LogicAssert.assertTrue(res.gameFinished == true, "Unexpected result " + res)
		b.buckets.eachWithIndex { value, index ->
			LogicAssert.assertTrue(expected[index] == value, "Unexpected result at ${index} --> ${expected[index]} != ${value}")
		}
		
		render(text:"OK")
		
	}
}
